//#include "stdafx.h"
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <sstream>
#include "colision.h"

Collision::Collision() {
}
 
Collision::~Collision() {
}
 
sf::IntRect Collision::GetAABB(const sf::Sprite& Object) {
    sf::Vector2f pos = Object.TransformToGlobal(sf::Vector2f(0, 0)); //TY
    sf::Vector2f size = Object.GetSize();
 
    float Angle = Object.GetRotation();
    if (Angle == 0.0f) {
        return sf::IntRect(static_cast<int> (pos.x),
                static_cast<int> (pos.y),
                static_cast<int> (pos.x + size.x),
                static_cast<int> (pos.y + size.y));
    }
    sf::Vector2f B(size.x, 0);
    sf::Vector2f C(size.x, size.y);
    sf::Vector2f D(0, size.y);
    B = RotatePoint(B, Angle);
    C = RotatePoint(C, Angle);
    D = RotatePoint(D, Angle);
    int Left = static_cast<int> (MinValue(0.0f, B.x, C.x, D.x));
    int Top = static_cast<int> (MinValue(0.0f, B.y, C.y, D.y));
    int Right = static_cast<int> (MaxValue(0.0f, B.x, C.x, D.x));
    int Bottom = static_cast<int> (MaxValue(0.0f, B.y, C.y, D.y));
    sf::IntRect AABB = sf::IntRect(Left, Top, Right, Bottom);
    AABB.Offset(static_cast<int> (pos.x), static_cast<int> (pos.y));
    return AABB;
}
 
float Collision::MinValue(float a, float b, float c, float d) {
    float min = a;
 
    min = (b < min ? b : min);
    min = (c < min ? c : min);
    min = (d < min ? d : min);
 
    return min;
}
 
float Collision::MaxValue(float a, float b, float c, float d) {
    float max = a;
 
    max = (b > max ? b : max);
    max = (c > max ? c : max);
    max = (d > max ? d : max);
 
    return max;
}
 
sf::Vector2f Collision::RotatePoint(const sf::Vector2f& Point, float Angle) {
    Angle = Angle * RADIANS_PER_DEGREE;
    sf::Vector2f RotatedPoint;
    RotatedPoint.x = Point.x * cos(Angle) + Point.y * sin(Angle);
    RotatedPoint.y = -Point.x * sin(Angle) + Point.y * cos(Angle);
    return RotatedPoint;
}
 
bool Collision::PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
    sf::IntRect Object1AABB = GetAABB(Object1);
    sf::IntRect Object2AABB = GetAABB(Object2);
    sf::IntRect Intersection;
 
    if (Object1AABB.Intersects(Object2AABB, &Intersection)) {
        if (AlphaLimit == 0) return true;
        sf::IntRect O1SubRect = Object1.GetSubRect();
        sf::IntRect O2SubRect = Object2.GetSubRect();
        sf::Vector2i O1SubRectSize(O1SubRect.GetWidth(), O1SubRect.GetHeight());
        sf::Vector2i O2SubRectSize(O2SubRect.GetWidth(), O2SubRect.GetHeight());
        sf::Vector2f o1v;
        sf::Vector2f o2v;
        for (int i = Intersection.Left; i < Intersection.Right; i++) {
            for (int j = Intersection.Top; j < Intersection.Bottom; j++) {
 
                o1v = Object1.TransformToLocal(sf::Vector2f(i, j)); 
                o2v = Object2.TransformToLocal(sf::Vector2f(i, j));
                if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
                        o1v.x < O1SubRectSize.x && o1v.y < O1SubRectSize.y &&
                        o2v.x < O2SubRectSize.x && o2v.y < O2SubRectSize.y) {
                    if ((Object1.GetPixel(static_cast<int> (o1v.x), static_cast<int> (o1v.y)).a > AlphaLimit) &&
                            (Object2.GetPixel(static_cast<int> (o2v.x), static_cast<int> (o2v.y)).a > AlphaLimit)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    return false;
}

